local log = {}

function prints(...)
	local args = {...}
	local records = {}
	local function _print(k, v, tm)
		if type(k) ~= "string" and type(k) ~= "number" then
			if not tostring(k) then
				k = "-unknown-key-"
			end
		end

		local tab = ""
		for i = 1, tm do
			tab = tab .. "    "
		end
		if type(v) == "string" then
			if type(k) == type("") then
				print(tab .. '["' .. k .. '"]' .. " = " .. '"' .. v .. '",')
			else
				print(tab .. "[" .. tostring(k) .. "]" .. " = " .. '"' .. v .. '",')
			end
		elseif type(v) == "number" then
			if type(k) == type("") then
				print(tab .. '["' .. k .. '"]' .. " = " .. v .. ",")
			else
				print(tab .. "[" .. tostring(k) .. "]" .. " = " .. v .. ",")
			end
		elseif type(v) == "boolean" then
			if type(k) == type("") then
				print(tab .. '["' .. k .. '"]' .. " = " .. tostring(v) .. ",")
			else
				print(tab .. "[" .. tostring(k) .. "]" .. " = " .. tostring(v) .. ",")
			end
		elseif type(v) == "table" then
			if records[v] then	-- recursive table check!
				if type(k) == type("") then
					print(tab .. '["' .. k .. '"]' .. " = " .. "[RECURSIVE TABLE],")
				else
					print(tab .. "[" .. tostring(k) .. "]" .. " = " .. "[RECURSIVE TABLE],")
				end
			else
				records[v] = true
				if type(k) == type("") then
					print(tab .. '["' .. k .. '"]' .. " = " .. "{")
				else
					print(tab .."[" .. tostring(k) .. "]" .. " = " .. "{")
				end
				for _k, _v in pairs(v) do
					_print(_k, _v, tm + 1)
				end
				print(tab .. "},")
			end
		else
			if type(k) == type("") then
				print(tab .. '["' .. k .. '"]' .. " = " .. tostring(v) or "UNKNOWN,")
			else
				print(tab .. "[" .. tostring(k) .. "]" .. " = " .. tostring(v) or "UNKNOWN,")
			end
		end
	end

	local len = 0
	for k, v in pairs(args) do
		if len < k then len = k end
	end

	for i = 1, len do
		if type(args[i]) == type{} then
			records[args[i]] = true
			print("{")
			for _k, _v in pairs(args[i]) do
				_print(_k, _v, 1)
			end
			print("}")
		else
			print(tostring(args[i]) or "UNKNOWN")
		end
		if i ~= len then
			print("\n")
		end
	end
end

local function concat(...)
	local args = {...}
	local records = {}

	local s = ''
	local function _p(k, v, tm)
		if type(k) ~= "string" and type(k) ~= "number" then
			if not tostring(k) then
				k = "-unknown-key-"
			end
		end

		local tab = ""
		for i = 1, tm do
			tab = tab .. "    "
		end
		if type(v) == "string" then
			if type(k) == type("") then
				s = s .. "\n" .. tab .. '["' .. k .. '"]' .. " = " .. '"' .. v .. '",'
			else
				s = s .. "\n" .. tab .. "[" .. tostring(k) .. "]" .. " = " .. '"' .. v .. '",'
			end
		elseif type(v) == "number" then
			if type(k) == type("") then
				s = s .. "\n" .. tab .. '["' .. k .. '"]' .. " = " .. v .. ","
			else
				s = s .. "\n" .. tab .. "[" .. tostring(k) .. "]" .. " = " .. v .. ","
			end
		elseif type(v) == "boolean" then
			if type(k) == type("") then
				s = s .. "\n" .. tab .. '["' .. k .. '"]' .. " = " .. tostring(v) .. ","
			else
				s = s .. "\n" .. tab .. "[" .. tostring(k) .. "]" .. " = " .. tostring(v) .. ","
			end
		elseif type(v) == "table" then
			if records[v] then	-- recursive table check!
				if type(k) == type("") then
					s = s .. "\n" .. tab .. '["' .. k .. '"]' .. " = " .. "[RECURSIVE TABLE],"
				else
					s = s .. "\n" .. tab .. "[" .. tostring(k) .. "]" .. " = " .. "[RECURSIVE TABLE],"
				end
			else
				records[v] = true
				if type(k) == type("") then
					s = s .. "\n" .. tab .. '["' .. k .. '"]' .. " = " .. "{"
				else
					s = s .. "\n" .. tab .."[" .. tostring(k) .. "]" .. " = " .. "{"
				end
				for _k, _v in pairs(v) do
					_p(_k, _v, tm + 1)
				end
				s = s .. "\n" .. tab .. "},"
			end
		else
			if type(k) == type("") then
				s = s .. "\n" .. tab .. '["' .. k .. '"]' .. " = " .. tostring(v) or "UNKNOWN,"
			else
				s = s .. "\n" .. tab .. "[" .. tostring(k) .. "]" .. " = " .. tostring(v) or "UNKNOWN,"
			end
		end
	end

	local len = 0
	for k, v in pairs(args) do
		if len < k then len = k end
	end

	for i = 1, len do
		if type(args[i]) == type{} then
			records[args[i]] = true
			s = s .. "{"
			for _k, _v in pairs(args[i]) do
				_p(_k, _v, 1)
			end
			s = s .. "\n" .. "}"
		else
			s = s .. (tostring(args[i]) or "UNKNOWN")
		end
		if i ~= len then
            s = s .. "    "
		end
	end
	return s
end

local LOG_LEVEL = {
    TRACE = 0,
    DEBUG = 1,
    INFO  = 2,
    WARN  = 3,
    ERROR = 4,
    FATAL = 5,
    SYS   = 6,
}

local log_level_info = {
    [LOG_LEVEL.TRACE] = { color = "\x1b[1;34m", head = "[TRACE]" },
    [LOG_LEVEL.DEBUG] = { color = "\x1b[1;36m", head = "[DEBUG]" },
    [LOG_LEVEL.INFO ] = { color = "",           head = "[INFO]"  },
    [LOG_LEVEL.WARN ] = { color = "\x1b[1;33m", head = "[WARN]"  },
    [LOG_LEVEL.ERROR] = { color = "\x1b[1;31m", head = "[ERROR]" },
    [LOG_LEVEL.FATAL] = { color = "\x1b[1;41m", head = "[FATAL]" },
    [LOG_LEVEL.SYS  ] = { color = "\x1b[1m",    head = "[SYS]"   },
}

local function _print(lv, message)
	if not lv then
		lv = LOG_LEVEL.SYS
	else
		lv = tonumber(lv)
	end

	local info = log_level_info[lv]
	local t = os.date("*t")
	print(string.format(
		"%s%04d-%02d-%02d %02d:%02d:%02d %s %s\x1b[0m", info.color,
		t.year, t.month, t.day, t.hour, t.min, t.sec,
		info.head, message))
end

log.print = function(...)
	print(concat(...))
end

-- --[[
log.trace = function(...)
	_print(LOG_LEVEL.TRACE, concat(...))
end

log.error = function(...)
	_print(LOG_LEVEL.ERROR, concat(...))
end

log.debug = function(...)
	_print(LOG_LEVEL.DEBUG, concat(...))
end

log.info = function(...)
	_print(LOG_LEVEL.INFO, concat(...))
end

log.warn = function(...)
	_print(LOG_LEVEL.WARN, concat(...))
end

log.fatal = function(...)
	_print(LOG_LEVEL.FATAL, concat(...))
end

log.sys = function(...)
	_print(LOG_LEVEL.SYS, concat(...))
end
--]]

return log
